package com.ruoyi.iot.service;

import com.influxdb.client.InfluxDBClient;
import com.influxdb.client.InfluxDBClientFactory;
import com.influxdb.client.WriteApi;
import com.influxdb.client.write.Point;
import com.influxdb.query.FluxRecord;
import com.influxdb.query.FluxTable;
import com.ruoyi.iot.domain.Coldefinetable;
import com.ruoyi.iot.vo.InfluxQueryResultVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.time.Instant;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.Date;
import java.util.List;

@Slf4j
@Service
public class InfluxService {

    private final InfluxDBClient client;

    public InfluxService() {
        this.client = InfluxDBClientFactory.create(
                "http://localhost:8086",                 // InfluxDB 地址
                "gW2wDHx1gZHOOXy5RrqBByGd15MsagVrmT9yThlTbCDiIlE6xAxEfmyuIPuyuX2OIWTw-E_42uAP3AC591H8Rw==".toCharArray(),              // token
                "ldkj",                              // org 名称
                "DEMO"                            // bucket 名称
        );
    }

    /**
     * 将采集数据写入 InfluxDB
     * @param point     点位对象
     * @param value     采集值（Boolean / Double）
     * @param timestamp 时间戳
     */
    public void writeData(Coldefinetable point, Object value, Instant timestamp) {
        // 对标签值进行转义处理，避免特殊字符引起问题
        String escapedPoint = escapeTagValue(point.getName());
        String escapedArea = escapeTagValue(point.getArea());
        String escapedIp = escapeTagValue(point.getIp());

        Point p = Point.measurement("sensor_data2")
                .addTag("point", escapedPoint)
                .addTag("area", escapedArea)
                .addTag("ip", escapedIp)
                .addField("value", convertValue(value));
                //.time(timestamp, WritePrecision.MS);

        log.info("实际写入的 Line Protocol：{}", p.toLineProtocol());

        try (WriteApi writeApi = client.getWriteApi()) {
            writeApi.writePoint(p);
            log.info("数据写入成功：{}", p);
        } catch (Exception e) {
            log.error("写入失败：{}", e.getMessage());
            e.printStackTrace();
        }
    }

    // 新增：标签值转义方法
    private String escapeTagValue(String value) {
        if (value == null) {
            return "";
        }
        // 转义逗号、等号和空格
        return value.replace("\\", "\\\\")
                .replace(",", "\\,")
                .replace("=", "\\=")
                .replace(" ", "\\ ");
    }


    /**
     * 将 Object 类型的值转为数字，用于 Influx 字段存储
     */
    private Number convertValue(Object value) {
        if (value instanceof Boolean) return ((Boolean) value) ? 1 : 0;
        if (value instanceof Number) return (Number) value;
        return Double.parseDouble(value.toString());
    }

    public List<InfluxQueryResultVO> querySensorData() {
        String flux = String.format(
                "from(bucket: \"DEMO\")\n" +
                        "  |> range(start: -10m)\n" +
                        "  |> filter(fn: (r) => r[\"_measurement\"] == \"sensor_data2\")\n" +
                        "  |> group(columns: [\"point\"])\n" +  // 按点位分组
                        "  |> sort(columns: [\"_time\"], desc: true)\n" +  // 倒序
                        "  |> yield(name: \"mean\")"
        );

        List<InfluxQueryResultVO> resultList = new ArrayList<>();

        try {
            List<FluxTable> tables = client.getQueryApi().query(flux);
            for (FluxTable table : tables) {
                for (FluxRecord record : table.getRecords()) {
                    InfluxQueryResultVO vo = new InfluxQueryResultVO();
                    vo.setTime(Date.from(record.getTime()));
                    vo.setValue(record.getValue() != null ? Double.parseDouble(record.getValue().toString()) : null);
                    vo.setPoint((String) record.getValueByKey("point"));
                    vo.setIp((String) record.getValueByKey("ip"));
                    vo.setArea((String) record.getValueByKey("area"));
                    resultList.add(vo);
                }
            }
        } catch (Exception e) {
            log.error("InfluxDB 查询失败: {}", e.getMessage());
            e.printStackTrace();
        }
        // 按时间倒序排序（最新的在前）
        resultList.sort(Comparator.comparing(InfluxQueryResultVO::getTime).reversed());
        return resultList;
    }
}

